/**
 * @file    memory.h
 * @author  Thomas Di'Meco and Matthieu Maugard
 * @brief   Memory et registers management
 */

#ifndef MEMORY_H_
#define MEMORY_H_

#include <stdlib.h>

#define MEMORY_SIZE      1000       ///< Memory size (in word)
#define REGISTERS_NUMBER 8          ///< Number of general registers
#define EMPTY_WORD       {.raw = 0} ///< Empty word macro

/**
 * Word union. This represent a word in our architecture. You can
 * access each part of the word using the inst substruct or the
 * entire word value with the raw subvariable
 */
typedef union
{
    /**
     * Represent the entire word raw value
     */
    int16_t raw;

    /**
     * Represent each part of the word
     */
    struct
    {
        u_int16_t codeop : 6; ///< Operation code
        u_int16_t mode   : 4; ///< Addressing mode
        u_int16_t src    : 3; ///< Source
        u_int16_t dest   : 3; ///< Destination

    } inst;

} word_t;


extern word_t  mem[MEMORY_SIZE];      ///< Global memory (size: MEMORY_SIZE words)
extern int16_t reg[REGISTERS_NUMBER]; ///< General registers
extern int16_t pc;                    ///< Program counter
extern int16_t sp;                    ///< Stack pointer
extern int16_t sr;                    ///< Status register


/**
 * Extract the source mode from the instruction mode
 * @param mode The instruction mode
 * @return The source mode
 */
int16_t get_src_mode (int16_t mode);

/**
 * Extract the destination mode from the instruction mode
 * @param mode The instruction mode
 * @return The destination mode
 */
int16_t get_dest_mode (int16_t mode);

/**
 * Combine the destination mode and the source mode into
 * the corresponding instruction mode
 * @param dest_mode The destination mode
 * @param src_mode The source mode
 * @return The instruction mode
 */
int16_t get_mode (int16_t dest_mode, int16_t src_mode);

/**
 * Returns true if mem is a valid memory address
 * @param mem The memory address
 * @return 1 if the memory address is valid, 0 otherwise
 */
int is_mem (int16_t mem);

/**
 * Returns true if reg is a valid register
 * @param reg The register number
 * @return 1 if the register is valid, 0 otherwise
 */
int is_reg (int16_t reg);

/**
 * Dump the current memory state to the standard output
 */
void dump_mem ();

/**
 * Dump registers to the standard output
 */
void dump_reg ();

/**
 * Convert a binary word into PROCSI mnemonic textual instruction
 * @param word The memory address of the word
 * @param str  The string buffer you want to store the result
 * @param size The size of the string buffer
 * @return     An error code != 0 if an error occured,
 *             0 otherwise
 */
int mnemonic_instruction (int16_t word, char * str, int size);

#endif /* MEMORY_H_ */
